import base64
import pickle

from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from cart import constants
from cart.serializers import CartSerializer, CartSKUSerializer, CartDelSerializer, CartSelectedSerializer
from goods.models import SKU


# Create your views here.


# POST /cart/
# 购物车
class CartView(APIView):
    def perform_authentication(self, request):
        '''视图跳过DFR框架认证过程'''
        pass

    def get(self, request):
        '''
        获取购物车数据
        1. 获取user
        2. 判断用户是否登录
            2.1 用户登录获取redis中的数据
            2.2 用户未登录获取cookie中的数据
        3. 根据sku_id查询商品数数据
        4. 将用户购物车商品序列化返回
        '''

        # 1. 获取user
        try:
            user = request.user
        except Exception:
            user = None

        # 2. 判断用户是否登录
        if user and user.is_authenticated:

            # 2.1 用户登录获取redis中的数据
            redis_conn = get_redis_connection('cart')

            # redis  hash 中获取购物车商品的id 和对应数量count
            cart_key = 'cart_%s' % user.id
            cart_redis = redis_conn.hgetall(cart_key)

            # redis set 中获取勾选状态
            cart_selected_key = 'cart_selected_%s' % user.id
            cart_selected_redis = redis_conn.smembers(cart_selected_key)

            # 组织数据
            cart_dict = {}
            for sku_id, count in cart_redis.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected_redis
                }



        else:
            # 2.2 用户未登录获取cookie中的数据
            # 获取cookie中的数据
            cookies_cart = request.COOKIES.get('cart')

            # 解析cookie中的数据
            if cookies_cart:
                cart_dict = pickle.loads(base64.b64decode(cookies_cart))
            else:
                cart_dict = {}

        # 3. 根据sku_id查询商品数数据
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)

        for sku in skus:
            # 给对象添加对象属性count 和 selected
            # 分别保存该商品在用户的购物车中添加数量和勾选状态
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 4. 将用户购物车商品序列化返回
        serializer = CartSKUSerializer(skus, many=True)
        return Response(serializer.data)

    def post(self, request):
        """
        购物车记录的添加:
        1. 获取参数并进行校验 完整性,商品是否存在,商品库存是否充足
        2. 保存用户购物车记录
            2.1 登录保存到redis中
            2.2 未登录保存到cookie中
        3. 返回应答,购物车保存成功
        """
        # 1. 获取参数并进行校验 完整性,商品是否存在,商品库存是否充足
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 获取校验后的数据
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']
        # 2. 保存用户购物车记录
        try:
            user = request.user
        except Exception:
            user = None

        if user:
            # 2.1 登录保存到redis中
            if user and user.is_authenticated:
                redis_coon = get_redis_connection('cart')

                # 在redis中hash元素中保存商品id 与count
                # 如果添加够该商品就数量累加
                cart_key = 'cart_%s' % user.id
                redis_coon.hincrby(cart_key, sku_id, count)
                # 在 set 中保存 勾选状态
                cart_selected_key = 'cart_selected_%s' % user.id
                redis_coon.sadd(cart_selected_key, sku_id)

                # 3. 返回应答,购物车保存成功
                return Response(serializer.data)


        else:
            # 2.2 未登录保存到cookie中
            # 获取cookie中购物车数据
            cookies_cart = request.COOKIES.get("cart")
            if cookies_cart:
                # 解析cookie中的数据
                cart_dict = pickle.loads(base64.b64decode(cookies_cart))
            else:
                cart_dict = {}

            # 保存用户购物车数据
            if sku_id in cart_dict:
                count += cart_dict['count']

            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            response = Response(serializer.validated_data)
            # 进行编码返回
            cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)
            # 3. 返回应答,购物车保存成功
            return response

    def put(self, requset):
        '''
        购物车数据修改
        1. 获取数据并进行校验(数据完整性,商品是否存在,商品库存是否足够)
        2. 判断用户是否登录
            2.1 用户登录修改redis中的数据
            2.2 用户未登录修改cookie中的数据
        3. 返回应答
        '''
        # 1. 获取数据并进行校验(数据完整性,商品是否存在,商品库存是否足够)
        serializer = CartSerializer(data=requset.data)
        serializer.is_valid(raise_exception=True)

        # 获取验证后的数据
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 2. 判断用户是否登录
        try:
            user = requset.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 2.1 用户登录修改redis中的数据
            redis_conn = get_redis_connection('cart')

            # 修改hash中的数据
            cart_key = 'cart_%s' % user.id
            redis_conn.hset(cart_key, sku_id, count)

            # 修改set中的数据
            cart_selected_key = 'cart_selected_%s' % user.id
            # selected 勾选就添加 没有勾选要移除
            if selected:
                redis_conn.sadd(cart_selected_key, sku_id)
            else:
                redis_conn.srem(cart_selected_key, sku_id)

            # 3. 返回应答
            return Response(serializer.data)

        else:
            response = Response(serializer.data)
            # 2.2 用户未登录修改cookie中的数据
            # 获取cookie中的数据
            cookie_cart = requset.COOKIES.get('cart')

            if not cookie_cart:
                return response

            # 进行解析
            cart_dict = pickle.loads(base64.b64decode(cookie_cart))

            if not cart_dict:  # {}
                return response

            # 修改cookie中的数据
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 进行编码
            cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart_data, max_age=constants.CART_COOKIE_EXPIRES)
            # 3. 返回应答
            return response

    def delete(self, request):
        '''
        购物车数据删除
        1. 获取数据 并进行校验
        2. 判断用户登录状况
            2.1 用户登录删除resid中的数据
            2.2 用户未登录删除cookie中的数据
        3. 返回响应
        '''
        # 1. 获取数据 并进行校验
        serializer = CartDelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        sku_id = serializer.validated_data['sku_id']
        try:
            user = request.user
        except Exception:
            user = None

        # 2. 判断用户登录状况
        if user and user.is_authenticated:
            # 2.1 用户登录删除resid中的数据
            redis_coon = get_redis_connection('cart')

            cart_key = 'cart_%s' % user.id
            redis_coon.hdel(cart_key, sku_id)

            cart_selected_key = 'cart_selected_%s' % user.id
            redis_coon.srem(cart_selected_key, sku_id)

            return Response(status=status.HTTP_204_NO_CONTENT)


            #     2.2 用户未登录删除cookie中的数据

        else:
            response = Response(status=status.HTTP_204_NO_CONTENT)
            cookies_cart = request.COOKIES.get('cart')

            if cookies_cart is None:
                return response

            # 解析购物车中数据
            cart_dict = pickle.loads(base64.b64decode(cookies_cart))  # {}

            # 删除购物车中对应商品数据
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                cookie_data = base64.b64encode(pickle.dumps(cart_dict)).decode()  # str

                # 设置购物车cookie信息
                response.set_cookie('cart', cookie_data, expires=constants.CART_COOKIE_EXPIRES)

            # 4. 返回应答，status=204
            return response


# /cart/selection/
class CartSelectAllView(APIView):
    def perform_authentication(self, request):
        '''视图跳过DFR框架认证过程'''
        pass

    def put(self, request):
        '''
        购物车全选与取消全选
        1. 获取数据 selected 校验完整性
        2. 根据selected 设置用户购物车勾选状态
            2.1 用户登录设置redis中的set
            2.2 用户未登录设置cookie中的数据
        3. 返回应答
        '''
        # 1. 获取数据 selected 校验完整性
        serializer = CartSelectedSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 2. 根据selected 设置用户购物车勾选状态
        selected = serializer.validated_data['selected']
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 2.1 用户登录设置redis中的set
            redis_conn = get_redis_connection('cart')
            # 获取所有的商品id
            cart_key = 'cart_%s' % user.id
            sku_ids = redis_conn.hkeys(cart_key)  # list

            cart_selected_key = 'cart_selected_%s' % user.id

            # 判断selected的动作
            if selected:
                # 全选
                redis_conn.sadd(cart_selected_key, *sku_ids)
            else:
                # 取消全选
                redis_conn.srem(cart_selected_key,  *sku_ids)
            return Response({'message': 'ok'})

        else:
            response = Response({'message': 'ok'})
            # 2.2 用户未登录设置cookie中的数据
            # 获取cookie中数据,解析
            cookies_cart = request.COOKIES.get('cart')
            if not cookies_cart:
                return response

            cart_dict = pickle.loads(base64.b64decode(cookies_cart))

            if not cart_dict:
                return response

            # 修改cookie中数据
            for sku_id in cart_dict.keys():
                cart_dict[sku_id]['selected'] = selected

            cookies_data = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cookies_data)
            return response



            # 3. 返回应答




